#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <sys/time.h>
#include "athread.h"

double ex[NX][NY+1];
double ey[NX+1][NY];
double hz[NX][NY];

//for check 
double ex1[NX][NY+1]; 
double ey1[NX+1][NY]; 
double hz1[NX][NY];
int iter,thread_num,num_x,num_y;
int task_id=0;
//int task_num[64]={0};
//int task_start[64]={0};
#ifdef PROFILING 
unsigned long slave_comp_count[64]={0};
unsigned long slave_dma_count[64]={0};
unsigned long slave_count[64]={0};
#endif
unsigned long rpcc()
{
  unsigned long time;
  asm("rtc %0":"=r"(time):);
  return time;
}
#define my_ceil(a,b) \
     (a%b==0)?a/b:a/b+1

extern SLAVE_FUN(func)();

void init_array(double ex[][NY+1],double ey[][NY], double hz[][NY])
{
    int i, j;
    for(i = 0; i < NX+1; i++)
        for(j = 0; j < NY; j++)
            ey[i][j] = (double)(i+1)/(j+1);
        
    for(i = 0; i < NX; i++)
        for(j = 0; j < NY+1; j++)
            ex[i][j] =(double)1/(i+j+1); 

    for(i = 0; i < NX; i++)
        for(j = 0; j < NY; j++)
            hz[i][j] = (double)1/(i+1)/(j+1);
}

int check()
{
    int i1,j1,t1;
    //init
    init_array(ex1,ey1,hz1); 
    //compute
    for(t1=0; t1<TMAX; t1++)
    {
        for(j1=0; j1<NY; j1++)
            ey1[0][j1] = t1;

        for(i1=1; i1<NX; i1++)
            for(j1=0; j1<NY; j1++)
                ey1[i1][j1] = ey1[i1][j1] - 0.5*(hz1[i1][j1]-hz1[i1-1][j1]);
         
        for(i1=0; i1<NX; i1++)
            for(j1=1; j1<NY; j1++)
                ex1[i1][j1] = ex1[i1][j1] - 0.5*(hz1[i1][j1]-hz1[i1][j1-1]);
            
        for(i1=0; i1<NX; i1++)
            for (j1=0; j1<NY; j1++)
                hz1[i1][j1]=hz1[i1][j1]-0.7*(ex1[i1][j1+1]-ex1[i1][j1]+ey1[i1+1][j1]-ey1[i1][j1]);
    }
    //check
    //loop1_ey
    for(j1=0; j1<NY; j1++) 
    {
        if(fabs(ey1[0][j1]-ey[0][j1])>1e-10)
        {
            printf("loop1-ey<%d,%d >: ",0,j1);
            printf("master=%f is incoistent with ",ey1[0][j1]);
            printf("slave=%f\n",ey[0][j1]);
            return 1;
        }
    }
    //loop2_ey
    for(i1=1; i1<NX; i1++)
        for(j1=0; j1<NY; j1++)
        {
            if(fabs(ey1[i1][j1]-ey[i1][j1])>1e-10)
            {   
                printf("loop2-ey<%d,%d >: ",i1,j1);
                printf("master=%f is incoistent with ",ey1[i1][j1]);
                printf("slave=%f\n",ey[i1][j1]);
                return 1;
            } 
        }
    //loop3_ex
    for(i1=0; i1<NX; i1++)
        for(j1=1; j1<NY; j1++)  
        {
            if(fabs(ex1[i1][j1]-ex[i1][j1])>1e-10)
            {   
                printf("loop3-ex<%d,%d >: ",i1,j1);
                printf("master=%f is incoistent with ",ex1[i1][j1]);
                printf("slave=%f\n",ex[i1][j1]);
                return 1;
            }
        }
    //loop4_hz
    for(i1=0;i1<NX;i1++)
        for(j1=0;j1<NY;j1++)
        {
            if(fabs(hz1[i1][j1]-hz[i1][j1])>1e-10)
            {
                printf("< %d,%d >: ",i1,j1);
                printf("%f is incoistent with ",hz1[i1][j1]);
                printf("%f\n",hz[i1][j1]);
                return 1;
            }	
        }
    printf("......check is right !......\n");
    return 0;
}

int main(int argc, char** argv)
{
    int i,j,k,t,n;
    //struct timeval start;
    //struct timeval end;
    //double total_time; 
    unsigned long start1,end1;
    unsigned long comp_count=0;
    unsigned long dma_count=0;
    unsigned long count=0;
    if(argc>1)
        thread_num=atoi(argv[1]);
    
    init_array(ex,ey,hz);
    printf("iter=%d,thread_num=%d\n",TMAX,thread_num);
    athread_init();
    {
        num_x=my_ceil(NX,TZ1);
        num_y=my_ceil(NY,TZ2);
    }
    //gettimeofday(&start,NULL);
    start1=rpcc();
    athread_spawn(func,0); 
    athread_join();
    end1=rpcc();
    
    printf("total_time: %ld\n",end1-start1);
    //gettimeofday(&end,NULL);
    athread_halt();
    //total_time = 0.0;
    //total_time+=(end.tv_sec-start.tv_sec)+(end.tv_usec-start.tv_usec)/1000000.0;
    //printf("total_time: %lf\n",total_time);
    printf("total_time: %ld\n",end1-start1);
#ifdef PROFILING     
    for (i=0;i<thread_num;i++)
    {
        comp_count+=slave_comp_count[i];
        dma_count+=slave_dma_count[i];
        //count+=slave_count[i];   
    }
    printf("comp_count:%ld\n",comp_count);
    printf("dma_count:%ld\n",dma_count);
    //printf("count:%ld\n",count);
    printf("\n");
#endif  
#ifdef CHECK  
if(check())
    {
        printf("error\n");
        exit(1);
    }
#endif
    return 0;
}
